<?php

namespace service\express;

use service\express\Contracts\DataSourceContract;
use service\express\Contracts\HttpRequestContract;
use service\express\Exceptions\DataSourceException;

abstract class DataSourceAbstract implements DataSourceContract
{
    /**
     * request uri
     *
     * @var string
     */
    protected $request_uri = '';

    /**
     * request uri tpl
     *
     * @var string
     */
    protected $request_uri_tpl = '';

    /**
     * request params
     *
     * @var array
     */
    protected $request_params = [];

    /**
     * origin return
     *
     * @var string
     */
    protected $origin_return;

    /**
     * error info
     *
     * @var string
     */
    protected $error;

    /**
     * http requester
     *
     * @var HttpRequestContract
     */
    protected static $requester;

    /**
     * supportted_brands
     *
     * @var array
     */
    protected $supportted_brands = [];

    /**
     * required_brand_paramter
     *
     * @var boolean
     */
    protected $required_brand_paramter = true;

    /**
     * required parameter fields
     *
     * @var array
     */
    protected $required_params = [
        'waybill_no',
        'brand',
    ];


    /**
     * constructor
     *
     * @param array               $params
     * @param HttpRequestContract $requester
     */
    public function __construct(array $params, HttpRequestContract $requester)
    {
        if(count($params) === 0 || !$this->requiredParamsCheck($params)){
            static::throwException('error parameters provided');
        }
        //需要知道传来的参数有什么 | 但是只要在请求里加上参数,一切都好了.
        $this->request_params = $params;
        //在请求里调用较好,根据情况构建url
        // $this->request_uri = $this->buildRequestUrl($params);
        static::$requester = $requester;
    }



    /**
     * getRequestUrl
     *
     * @return string
     */
    public function getRequestUrl()
    {
        return $this->request_uri;
    }

    /**
     * getData from
     *
     * @param string $waybill_no
     * @param string|null $brand
     * @return array|boolean
     */
    abstract public function getData($waybill_no, $brand = null);

    /**
     * getOriginReturn
     *
     * @return string|null
     */
    public function getOriginReturn()
    {
        return $this->origin_return;
    }

    /**
     * getError
     *
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * isSupportedBrand
     *
     * @param  string  $brand
     * @return boolean
     */
    public function isSupportedBrand($brand)
    {
        return is_scalar($brand) ? is_set($this->supportted_brands[$brand]) : false;
    }

    /**
     * isRequiredBrand
     *
     * @return boolean
     */
    public function isRequiredBrand()
    {
        return $this->required_brand_paramter;
    }

    /**
     * requiredParamsCheck 参数是否包含必备的
     *
     * @param  array  $params
     * @return boolean
     */
    protected function requiredParamsCheck(array $params)
    {
        return !(bool) array_diff_key(array_flip((array)$this->required_params), $params);
    }

    /**
     * parseResponse
     * handle the data source response
     *
     * @param  string $data
     * @return array
     */
    abstract protected function parseResponse($data = null);

    /**
     * setError
     *
     * @param mixed $error
     * @param string|null $key
     */
    protected function setError($error, $key = null)
    {
        $this->error = $error;
        // if(!is_scalar($key)){
        //     $key = data('Y_m_d_H_i_s').mt_rand(1000, 9999);
        // }
        // $this->error[$key] = $error;
    }

    /**
     * buildRequestUrl
     *
     * @param  array  $params
     * @return string
     */
    protected function buildRequestUrl(array $params)
    {
        if(mb_substr_count($this->request_uri_tpl, '%s') !== count($params)){
            static::throwException('error parameters provided for url');
        }
        return $this->request_uri = vsprintf($this->request_uri_tpl, $params);
    }

    /**
     * throw a DataSource Exception
     *
     * @param  string  $msg
     * @param  integer $code
     * @param  throwable|null $previous
     * @return void
     */
    protected static function throwException($msg, $code = 1, $previous = null)
    {
        throw new DataSourceException($msg, $code, $previous);
    }
}

